package com.ptadmin.report.executor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.mws.model.IdList;
import com.amazonaws.mws.model.TypeList;
import com.ptadmin.report.ConfigurationManager;
import com.ptadmin.report.mws.GetReportRequestListWrapper;
import com.ptadmin.report.mws.GetReportWrapper;
import com.ptadmin.report.util.ReportCategory;
import com.ptadmin.report.util.ReportExt;
import com.ptadmin.report.util.ReportMapping;
import com.ptadmin.report.util.ReportPair;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

public class GetReportsExecutor {

	private static final Logger logger = LoggerFactory.getLogger(GetReportsExecutor.class);
	
	private List<GetReportsParameter> parameters;
	private long interval = ConfigurationManager.getInstance().getPropertiesConfig().getLong("getreport.interval");

	private GetReportsExecutor(Builder builder) {
		this.parameters = new ArrayList<GetReportsParameter>();

		if (builder.merchantIdList.size() != builder.sellerDevAuthTokenList.size()) {
			throw new RuntimeException("builder error, merchantId size is not equal to sellerDevAuthToken size...");
		}

		for (int i = 0; i < builder.merchantIdList.size(); i++) {
			GetReportsParameter p = new GetReportsParameter();
			p.setMerchantId(builder.merchantIdList.get(i));
			p.setMwsAuthToken(builder.sellerDevAuthTokenList.get(i));
			
			if (builder.reportTypeList.size() > 0) {
				p.setReportTypeList(new TypeList(builder.reportTypeList));
			}
			
			if (builder.reportRequestIdList.size() > 0) {
				p.setReportRequestIdList(new IdList(builder.reportRequestIdList));
			}
			this.parameters.add(p);
		}
	}

	public static class Builder {
		private List<String> merchantIdList = new ArrayList<String>();
		private List<String> sellerDevAuthTokenList = new ArrayList<String>();
		private List<String> reportTypeList = new ArrayList<String>();
		private List<String> reportRequestIdList = new ArrayList<String>();

		public Builder with(String merchantId, String sellerDevAuthToken) {
			this.merchantIdList.add(merchantId);
			this.sellerDevAuthTokenList.add(sellerDevAuthToken);
			return this;
		}

		public Builder withReportType(String reportType) {
			this.reportTypeList.add(reportType);
			return this;
		}

		public Builder withReportRequestId(String reportRequestId) {
			this.reportRequestIdList.add(reportRequestId);
			return this;
		}
		
		public GetReportsExecutor build() {
			GetReportsExecutor executor = new GetReportsExecutor(this);
			return executor;
		}
	}

	@Getter
	@Setter
	@NoArgsConstructor
	@AllArgsConstructor
	@ToString
	private class GetReportsParameter {
		private String merchantId;
		private String mwsAuthToken;

		private IdList reportRequestIdList;
		private TypeList reportTypeList;
	}

	public List<String> execute() {
		// GetReportsRequest
		List<String> reportFilePathList = new ArrayList<String>();
		for (GetReportsParameter p : parameters) {
			logger.info(String.format(">>>>>>>>> processing GetReportsParameter: %s", p.toString()));
			while (true) {
				try {
					logger.info(String.format(">>>>>>>>> sleeping %s ...", interval));
					Thread.sleep(interval);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// GetReportRequestList
				GetReportRequestListWrapper getReportRequestList = new GetReportRequestListWrapper();
				getReportRequestList.buildRequest(p.getMerchantId(), p.getMwsAuthToken(), p.getReportRequestIdList(),
						p.getReportTypeList());
				
				getReportRequestList.invokeRequest();
				getReportRequestList.printResponse();
				
				// Process reportId with done status
				Map<String, String> reportIdListDoneStatus = getReportRequestList.getReportIdWithDone();
				for (Map.Entry<String, String> entry : reportIdListDoneStatus.entrySet()) {
					String reportId = entry.getKey();
					String reportType = entry.getValue();
					
					logger.info(String.format(">>>>>>>>> processing reportId: %s, reportType: %s", reportId, reportType));
					GetReportWrapper getReport = new GetReportWrapper();
					
					ReportExt reportExt = ReportMapping.getReportExt(reportType);
					ReportCategory reportCategory = ReportMapping.getReportCategory(reportType);
					if (reportCategory == null) {
						throw new RuntimeException(String.format("report category is null, please check ReportMapping for report type: %s", reportType));
					}
					
					String saveFilePath = reportCategory.toString() + "_" + reportId + "_" + reportExt.toString();
					
					getReport.buildRequest(p.getMerchantId(), p.getMwsAuthToken(), reportId, saveFilePath);
					getReport.invokeRequest();
					getReport.printResponse();
					reportFilePathList.add(saveFilePath);
				}
//				for (String reportId : reportIdListDoneStatus) {
//					logger.info(String.format(">>>>>>>>> processing reportId: %s", reportId));
//					GetReportWrapper getReport = new GetReportWrapper();
//					getReport.buildRequest(p.getMerchantId(), p.getMwsAuthToken(), reportId, reportId);
//					getReport.invokeRequest();
//					getReport.printResponse();
//				}
				
				// Process reportId with done with NO data status
				Map<String, String> reportIdListWithNoDataDone = getReportRequestList.getReportIdWithNoDataDone();
				
				if (reportIdListDoneStatus.size() + reportIdListWithNoDataDone.size() >= p.reportRequestIdList.getId().size()) {
					logger.info(String.format(">>>>>>>>> reports done with size %s", p.reportRequestIdList.getId().size()));
					break;
				}
			}
		}
		return reportFilePathList;
	}
	
	public static void main(String... args) {
		GetReportsExecutor.Builder builder = new GetReportsExecutor.Builder();
		builder.with("A2N95VZZXMVRLW", "amzn.mws.52b2d181-1d65-65a8-04f7-e12ce26cfad5");
		builder.withReportRequestId("15695774047018090");
		List<String> reportFilePathList = builder.build().execute();
//		builder.withReportType(reportType);
//		ProcessReportsExecutor executor = new ProcessReportsExecutor();
//		executor.execute("report.xml");
	}
}
